#ifndef VIOSAPI_H
#define VIOSAPI_H

#include <BaseTsd.h>

#include "VioSConn.h"

enum VioSConnOpcode {
    NONE = VIOS_CONN_OPCODE_NONE,
    GET_PEER_STATE = VIOS_CONN_OPCODE_GET_PEER_STATE,
    REPORT_STATE = VIOS_CONN_OPCODE_REPORT_STATE,
};

enum VioSConnState {
    STATE_BROKEN = VIOS_CONN_STATE_BROKEN,
    STATE_UNKNOWN = VIOS_CONN_STATE_UNKNOWN,
    STATE_CONNECTING = VIOS_CONN_STATE_CONNECTING,
    STATE_CONNECTED = VIOS_CONN_STATE_CONNECTED,
    STATE_STOPPED = VIOS_CONN_STATE_STOPPED,
};

enum VioSOpStatus {
    SUCCESS,
    FAILURE,
    BROKEN_CONN,
    BROKEN_PROTOCOL,
    TIMEOUT,
    DISCONNECTED,
};

class VioSAPI {
public:
    VioSAPI() : m_handle(INVALID_HANDLE_VALUE),
                m_bInitialized(FALSE),
                m_hostPortIdx(-1) { };
    ~VioSAPI();
    VioSOpStatus ReadAllTimed(PVOID buf, DWORD readSz, INT timeoutMs);
    BOOL Write(PVOID buf, DWORD& writeSz);
    BOOL InitDev(INT hostPortIdx);
    BOOL PurgeIO();
    HANDLE GetHandle();

    VioSOpStatus DropLeftData();
    VioSOpStatus Connect(INT numRetry);
    VioSOpStatus Disconnect();

    VioSOpStatus RecvPacket(PVOID pktBuf, DWORD pktBufSz, INT readTimeoutMs);
    VioSOpStatus SendPacket(PVOID pktBuf, DWORD writeSz, INT totalTimeoutMs);
private:
    HANDLE m_handle;
    BOOL m_bInitialized;
    INT m_hostPortIdx;
    VioSConnState m_state{VioSConnState::STATE_CONNECTING};
    VioSConnState m_peerState{VioSConnState::STATE_UNKNOWN};

    BOOL GetPortHandle(BOOL ovrl, INT hostPortIdx);

    VioSOpStatus ReadTimed(PVOID buf, DWORD &readSz, INT timeoutMs);
    VioSOpStatus WriteTimed(PVOID buf, DWORD &writeSz, INT timeoutMs);
    VioSOpStatus WriteAllTimed(PVOID buf, DWORD writeSz, INT timeoutMs);

    VioSOpStatus ReportState();
    VioSOpStatus ReportGetPeerState();

    VioSOpStatus ProcessConnectPacket(PVOID pktHeader);
};

#endif // VIOSAPI_H